對前端工程師來說,串接api應該是超級常見的事了吧,我們今天就用axios來寫useFetch來控制data、loading與錯誤吧
import axios, { Method, AxiosRequestConfig } from "axios";
import { useEffect, useState } from "react";
type UseFetchProps = {
method?: Method;
options?: AxiosRequestConfig;
};
export function useFetch<T>(
url: string,
{ method, options }: UseFetchProps = { method: "GET" }
) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string>("");
async function fetchApi() {
try {
setLoading(true);
const res = await axios({ method, url, ...options });
setData(res.data);
} catch (err) {
console.error(err);
setError(err.message);
} finally {
setLoading(false);
}
}
useEffect(() => {
fetchApi();
}, [url]);
return { data, loading, error };
}
因為基礎版的應該大家都算熟悉了,我就不多做介紹了,我們有兩個參數,url
是必填的,method與option都是選填,method預設是用GET
,需要用POST
再傳入method就好,大部分的前幾天都有提過,應該不會太困難,Method
與AxiosRequestConfig
的這個Type是axios給的,我們不需要自行定義或者用泛型
但基礎版有時候在我們實際上可能不夠用,所以我又寫了一個進階版
更多的是我添加了以下功能
authorization token
import axios, { AxiosRequestConfig, Method } from "axios";
import { useEffect, useState, useRef } from "react";
// 用來儲存緩存的數據
const cache: Record<string, any> = {};
type UseFetchProps = {
url: string;
method?: Method;
headers?: Record<string, string>;
options?: AxiosRequestConfig;
};
type UseFetchState<T> = {
data: T | null;
loading: boolean;
error: {
message: string;
code?: number;
} | null;
};
export function useFetchAPI<T>(props: UseFetchProps): UseFetchState<T> {
const { url, method = "GET", headers, options } = props;
const cacheKey = useRef(`${method}-${url}-${JSON.stringify(options)}`);
const [state, setState] = useState<UseFetchState<T>>({
data: null,
loading: true,
error: null,
});
useEffect(() => {
const controller = new AbortController();
// 檢查緩存
if (cache[cacheKey.current]) {
setState({
data: cache[cacheKey.current],
loading: false,
error: null,
});
return;
}
// 發出新請求
const fetchData = async () => {
try {
const res = await axios({
method,
url,
headers,
signal: controller.signal,
...options,
});
// 更新緩存
cache[cacheKey.current] = res.data;
setState({
data: res.data,
loading: false,
error: null,
});
} catch (error) {
setState({
data: null,
loading: false,
error: {
message: error.message,
code: error.response?.status,
},
});
}
};
fetchData();
return () => {
controller.abort();
};
}, [url, method, headers, options]);
return state;
}
當然還有很多可以加的
例如:
react-query
的refetch
這些都可以自己嘗試,並且自己試試看寫出測試,明天就來教學如何寫api的測試摟~